const DIFF = Symbol("GitObject Private");
const Type = ["CREATE", "REMOVE", "CHANGE"];

// 借鉴了 microdiff 插件的格式
// 原子操作：每一个操作都会认定为一个 Record 实例
class Record {
    constructor({ type, path, value, description = "" }) {
        if (!Type.includes(type)) {
            throw new Error(
                `Git Object Record Error: type ${type} is not allowed`
            );
        }
        Object.assign(this, { type, path, value, description });
    }
    time = new Date().getTime();
}
import set from "lodash-es/set";
import unset from "lodash-es/unset";
import get from "lodash-es/get";
import _castPath from "lodash-es/_castPath";
export default class GitObject {
    [DIFF] = [];
    constructor(origin = null) {
        this.add(null, origin);
    }
    now = {};
    cursor = -1;
    get(path) {
        return get(this.now, path);
    }
    review(index = this.cursor) {
        if (index < 0 || index > this[DIFF].length - 1) return false;
        if (index === this.cursor) return true;

        let diff = this[DIFF].slice(
            index > this.cursor ? this.cursor + 1 : ((this.now = {}), 0),
            index + 1
        );

        diff.forEach((slide) => this._command(slide));
        this.cursor = index;
        return this.now;
    }
    // TODO 没有进行 CHANGE 和 CREATE 的区分
    add(path, value, { isRecord = true } = {}) {
        // ! null 被定义为对整个对象赋值
        if (path === null) {
            this.now = value;
        } else {
            set(this.now, path, value);
        }
        if (isRecord) this._recording({ type: "CHANGE", path, value });
    }
    delete(path, { isRecord = true } = {}) {
        unset(this.now, path);
        if (isRecord) this._recording({ type: "REMOVE", path });
    }
    _isNow() {
        return this.cursor === this[DIFF].length - 1;
    }
    _recording({ type, path, value }) {
        if (this._isNow()) {
            this.cursor++;
        } else {
            throw new Error(
                "GitObject: You are not in the last version of this ObjectBranch"
            );
        }
        this[DIFF].push(
            new Record({
                type,
                path: path === null ? null : _castPath(path),
                value: JSON.stringify(value),
            })
        );
    }
    // 将 record 转化为对内对象的操作
    _command({ type, path, value }) {
        switch (type) {
            case "CHANGE":
            case "CREATE":
                this.add(path, JSON.parse(value), { isRecord: false });
                break;
            case "REMOVE":
                this.delete(path, { isRecord: false });
        }
    }
}
